home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / jnos110g.zip / CONVERS.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  51KB  |  1,772 lines

  1. /* convers server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  * ported to NOS by PE1NMB - 920120
  4.  * Mods by PA0GRI
  5.  * Cleanup, and additional mods by WG7J
  6.  */
  7.   
  8. #include <time.h>
  9. #include <ctype.h>
  10. #ifdef  UNIX
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #endif
  14. #ifdef MSDOS
  15. #include <io.h>
  16. #endif
  17. #include "global.h"
  18. #ifdef CONVERS
  19. #include "mailbox.h"
  20. #include "netuser.h"
  21. #include "pktdrvr.h"
  22. #include "timer.h"
  23. #include "cmdparse.h"
  24. #include "usock.h"
  25. #include "socket.h"
  26. #include "session.h"
  27. #include "files.h"
  28. #include "mailutil.h"
  29.   
  30. #define LINK    1
  31. #define space
  32.   
  33. char Chostname[CNAMELEN+1];
  34. void conv_incom __ARGS((int s,void *t,void *p));
  35. int ConvUsers;
  36. int ConvHosts;
  37.   
  38. #ifdef space
  39. static char cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
  40. #else
  41. static char cnumber[] = "* range 0..%d.\n";
  42. #endif
  43.   
  44. #define MAXCHANNEL  32767
  45. #define LINELEN     256
  46. /* The convers daemon stack needs to be AT LEAST 4 times the LINELEN !
  47.  * since quiet a few of the commands have local vars of size 2 or 3 * LINELEN.
  48.  */
  49. #define CDAEMONSTACK 2048
  50. #define CLINKSTACK 1024
  51. #define MAX_WAITTIME    (60*60*3)
  52. #define NAMELEN 10
  53.   
  54. struct convection {
  55.     int  type;          /* Connection type */
  56. #define CT_UNKNOWN      0
  57. #define CT_USER         1
  58. #define CT_HOST         2
  59. #define CT_CLOSED       3
  60.     char  name[NAMELEN+1];         /* Name of user or host */
  61.     char  host[NAMELEN+1];         /* Name of host where user is logged on */
  62.     struct convection *via;     /* Pointer to neighbor host */
  63.     char *data;                 /* room for some personal data */
  64.     int channel;            /* Channel number */
  65.     int32 time;         /* Connect time */
  66.     int maxq;           /* Maximum outstanding data before link reset */
  67.     int locked;         /* Set if mesg already sent */
  68.     int fd;             /* Socket descriptor */
  69.     int flags;          /* User flags */
  70. #define CLOSE_SOCK  1
  71. #define USE_SOUND   2
  72.     /* This buffer is only needed for local users; a lot of space is wasted
  73.      * for users from other hosts (256 bytes per user!). Fixed 930728 - WG7J
  74.      * char ibuf[LINELEN];
  75.      */
  76.     char *ibuf;                      /* Input buffer */
  77.     unsigned long received;          /* Number of bytes received */
  78.     unsigned long xmitted;           /* Number of bytes transmitted */
  79.     struct convection *next;    /* Linked list pointer */
  80. };
  81.   
  82. #define CM_UNKNOWN  (1 << CT_UNKNOWN)
  83. #define CM_USER     (1 << CT_USER)
  84. #define CM_HOST     (1 << CT_HOST)
  85. #define CM_CLOSED   (1 << CT_CLOSED)
  86.   
  87. #define NULLCONNECTION  ((struct convection *) 0)
  88.   
  89. static struct convection *convections;
  90.   
  91. struct permlink {
  92.     char name[NAMELEN+1];   /* Name of link */
  93.     int32 addr;             /* address to link to */
  94.     struct convection *convection;  /* Pointer to associated connection */
  95.     int32 statetime;        /* Time of last (dis)connect */
  96.     int  tries;         /* Number of connect tries */
  97.     int32 waittime;         /* Time between connect tries */
  98.     int32 retrytime;        /* Time of next connect try */
  99.     int fd;             /* socket descriptor */
  100.     struct permlink *next;      /* Linked list pointer */
  101. };
  102. #define NULLPERMLINK ((struct permlink *) 0)
  103.   
  104. struct filter_link {
  105.     struct filter_link *next;
  106.     int32 addr;
  107. };
  108. #define NULLFL ((struct filter_link *) 0)
  109.   
  110. #ifdef LINK
  111. struct proc *Linker;
  112. static void connect_permlinks __ARGS((int a,void *b,void *c));
  113. static void update_permlinks __ARGS((char *name,struct convection *cp));
  114. #endif
  115.   
  116. static void free_connection __ARGS((register struct convection *cp));
  117. static char *formatline __ARGS((char  *prefix,char *text));
  118. static char  *timestring __ARGS((long  gmt));
  119. static void clear_locks __ARGS((void));
  120. static void send_msg_to_user __ARGS((char *fromname,char *toname,char *text));
  121. static void send_user_change_msg __ARGS((char *name,char *host,int oldchannel,int newchannel));
  122. static void send_invite_msg __ARGS((char *fromname,char *toname,int channel));
  123. static void personal_command __ARGS((struct convection *cp));
  124. static void bye_command __ARGS((struct convection *cp));
  125. static void send_msg_to_channel __ARGS((char *fromname,int channel,char *text));
  126. static void free_closed_connections __ARGS((void));
  127. static struct convection *alloc_connection __ARGS((int fd));
  128. static void process_commands __ARGS((struct convection *cp,struct mbx *m));
  129. static void set_personal __ARGS((struct convection *cp));
  130. static void version_command __ARGS((struct convection *cp));
  131.   
  132. static struct filter_link *Filterlinks;
  133. static int FilterMode;
  134. static struct permlink *permlinks;
  135. extern char Ccall[AXALEN];
  136.   
  137. static int docfilter __ARGS((int argc,char *argv[],void *p));
  138. static int dochostname __ARGS((int argc,char *argv[],void *p));
  139. static int dociface __ARGS((int argc,char *argv[],void *p));
  140. static int doconfcall __ARGS((int argc,char *argv[],void *p));
  141. static int doclink __ARGS((int argc,char *argv[],void *p));
  142. static int doct4 __ARGS((int argc,char *argv[],void *p));
  143. static int docmaxwait __ARGS((int argc,char *argv[],void *p));
  144. static int dohmaxq __ARGS((int argc,char *argv[],void *p));
  145. static int doumaxq __ARGS((int argc,char *argv[],void *p));
  146. static int dotdisc __ARGS((int argc,char *argv[],void *p));
  147. static int docdefaultchannel __ARGS((int argc,char *argv[],void *p));
  148.   
  149. static struct cmds DFAR Ccmds[] = {
  150.     "channel",  docdefaultchannel, 0, 0, NULLCHAR,
  151.     "filter",   docfilter,  0, 0, NULLCHAR,
  152.     "hmaxq",    dohmaxq,    0, 0, NULLCHAR,
  153.     "hostname", dochostname,0, 0, NULLCHAR,
  154.     "interface",dociface,   0, 0, NULLCHAR,
  155.     "maxwait",  docmaxwait, 0, 0, NULLCHAR,
  156. #ifdef AX25
  157.     "mycall",   doconfcall, 0, 0, NULLCHAR,
  158. #endif
  159. #ifdef LINK
  160.     "link",     doclink,    0, 0, NULLCHAR,
  161. #endif
  162. #ifdef AX25
  163.     "t4",       doct4,      0, 0, NULLCHAR,
  164. #endif
  165.     "tdisc",    dotdisc,    0, 0, NULLCHAR,
  166.     "umaxq",    doumaxq,    0, 0, NULLCHAR,
  167.     NULLCHAR,
  168. };
  169.   
  170. /* Multiplexer for top-level convers command */
  171. int
  172. doconvers(argc,argv,p)
  173. int argc;
  174. char *argv[];
  175. void *p;
  176. {
  177.     return subcmd(Ccmds,argc,argv,p);
  178. }
  179.   
  180. #ifdef AX25
  181. /* Display or change our AX.25 conference call */
  182. static int
  183. doconfcall(argc,argv,p)
  184. int argc;
  185. char *argv[];
  186. void *p;
  187. {
  188.     char tmp[AXBUF];
  189.   
  190.     if(argc < 2){
  191.         tprintf("%s\n",pax25(tmp,Ccall));
  192.         return 0;
  193.     }
  194.     if(setcall(Ccall,argv[1]) == -1)
  195.         return -1;
  196.     return 0;
  197. }
  198.   
  199. int32 CT4init = 7200;   /* 2 hours default */
  200.   
  201. /* Set link redundancy timer */
  202. static int
  203. doct4(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     return setlong(&CT4init,"Conf. redundancy timer (sec)",argc,argv);
  209. }
  210. #endif /* AX25 */
  211.   
  212. int32 CMaxwait = MAX_WAITTIME;
  213.   
  214. /* Set maxwait time for timed out links */
  215. static int
  216. docmaxwait(argc,argv,p)
  217. int argc;
  218. char *argv[];
  219. void *p;
  220. {
  221.     return setlong(&CMaxwait,"Re-link max wait (sec)",argc,argv);
  222. }
  223.   
  224. int HMaxQ = 5*1024;
  225.   
  226. /* Set max qlimit for host links */
  227. static int
  228. dohmaxq(argc,argv,p)
  229. int argc;
  230. char *argv[];
  231. void *p;
  232. {
  233.     return setint(&HMaxQ,"Max. Host Queue (bytes)",argc,argv);
  234. }
  235.   
  236. int UMaxQ = 1024;
  237.   
  238. /* Set max qlimit for user links */
  239. static int
  240. doumaxq(argc,argv,p)
  241. int argc;
  242. char *argv[];
  243. void *p;
  244. {
  245.     return setint(&UMaxQ,"Max. User Queue (bytes)",argc,argv);
  246. }
  247.   
  248. int CDefaultChannel;
  249.   
  250. /* Set the initial channel */
  251. static int
  252. docdefaultchannel(argc,argv,p)
  253. int argc;
  254. char *argv[];
  255. void *p;
  256. {
  257.     return setint(&CDefaultChannel,"Default channel",argc,argv);
  258. }
  259.   
  260. int32 Ctdiscinit;
  261.   
  262. /* Set convers redundancy timer */
  263. static int
  264. dotdisc(argc,argv,p)
  265. int argc;
  266. char *argv[];
  267. void *p;
  268. {
  269.     return setlong(&Ctdiscinit,"redundancy timer (sec)",argc,argv);
  270. }
  271.   
  272. static int
  273. dochostname(argc,argv,p)
  274. int argc;
  275. char *argv[];
  276. void *p;
  277. {
  278.     if(argc == 1)
  279.         tprintf("%s\n",Chostname);
  280.     else {
  281.         strncpy(Chostname,argv[1],NAMELEN);
  282.         Chostname[CNAMELEN] = '\0';
  283.     }
  284.     return 0;
  285. }
  286.   
  287. static int
  288. docfilter(argc,argv,p)
  289. int argc;
  290. char *argv[];
  291. void *p;
  292. {
  293.     int32 addr;
  294.     struct filter_link *fl;
  295.   
  296.     if(argc == 1) {
  297.         if(Filterlinks) {
  298.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  299.             for(fl=Filterlinks;fl;fl=fl->next)
  300.                 tprintf("%s\n",inet_ntoa(fl->addr));
  301.         }
  302.         return 0;
  303.     }
  304.     if(!stricmp(argv[1],"mode")) {
  305.         if(argc == 2)
  306.             tprintf("Mode is: %s\n", FilterMode ? "Accept" : "Refuse");
  307.         else {
  308.             if(*argv[2] == 'a' || *argv[2] == 'A')
  309.                 FilterMode = 1;
  310.             else
  311.                 FilterMode = 0;
  312.         }
  313.         return 0;
  314.     }
  315.     if((addr = resolve(argv[1])) == 0) {
  316.         tprintf(Badhost,argv[1]);
  317.         return 1;
  318.     }
  319.     /* check to see if we already have this in the list */
  320.     for(fl=Filterlinks;fl;fl=fl->next)
  321.         if(fl->addr == addr)
  322.             return 0;       /* already have this one ! */
  323.   
  324.     /* Seems like a new one */
  325.     fl = (struct filter_link *)callocw(1,sizeof(struct filter_link));
  326.     fl->addr = addr;
  327.     fl->next = Filterlinks;
  328.     Filterlinks = fl;
  329.     return 0;
  330. }
  331.   
  332. #ifdef LINK
  333. static int
  334. doclink(argc,argv,p)
  335. int argc;
  336. char *argv[];
  337. void *p;
  338. {
  339.     int32 addr;
  340.     struct permlink *pl;
  341.   
  342.     if(argc == 1) {
  343.         for(pl=permlinks;pl;pl=pl->next)
  344.             tprintf("%10s: %s\n",pl->name,inet_ntoa(pl->addr));
  345.         return 0;
  346.     }
  347.     if((addr = resolve(argv[1])) == 0) {
  348.         tprintf(Badhost,argv[1]);
  349.         return 1;
  350.     }
  351.     /* check to see if we already have a link to such animal,
  352.      * this happens when we stop and restart the server - WG7J
  353.      */
  354.     for(pl=permlinks;pl;pl=pl->next)
  355.         if(pl->addr == addr)
  356.             return 1;       /* already have this one ! */
  357.   
  358.     /* Seems like a new link ! Go add it */
  359.     pl = (struct permlink *)callocw(1,sizeof(struct permlink ));
  360.     pl->addr = addr;
  361.     pl->next = permlinks;
  362.     permlinks = pl;
  363.     if(argc > 2) {
  364.         strncpy(pl->name,argv[2],NAMELEN);
  365.         update_permlinks(pl->name,NULLCONNECTION);
  366.     } else
  367.         strcpy(pl->name,"Unknown");
  368.     if(!Linker)
  369.         Linker = newproc("Clinker",CLINKSTACK,connect_permlinks,0,0,NULL,0);
  370.   
  371.     return 0;
  372. }
  373. #endif
  374.   
  375. static int
  376. dociface(argc,argv,p)
  377. int argc;
  378. char *argv[];
  379. void *p;
  380. {
  381.     return setflag(argc,argv[1],IS_CONV_IFACE,argv[2]);
  382. }
  383.   
  384. /* Stop convers server */
  385. int
  386. conv0(argc,argv,p)
  387. int argc;
  388. char *argv[];
  389. void *p;
  390. {
  391.     int16 port;
  392.   
  393.     if(argc < 2)
  394.         port = IPPORT_CONVERS;
  395.     else
  396.         port = atoi(argv[1]);
  397. #ifdef LINK
  398.     if(Linker)
  399.         killproc(Linker);
  400. #endif
  401.     return stop_tcp(port);
  402. }
  403.   
  404. /* Start up convers server */
  405. int
  406. conv1(argc,argv,p)
  407. int argc;
  408. char *argv[];
  409. void *p;
  410. {
  411.     int16 port;
  412.   
  413.     if(argc < 2)
  414.         port = IPPORT_CONVERS;
  415.     else
  416.         port = atoi(argv[1]);
  417.   
  418.     return start_tcp(port,"CONVERS Server",conv_incom,CDAEMONSTACK);
  419. }
  420.   
  421. static void
  422. free_connection(cp)
  423. register struct convection *cp;
  424. {
  425.     register struct permlink *p;
  426.   
  427.     for(p = permlinks; p; p = p->next)
  428.         if(p->convection == cp)
  429.             p->convection = NULLCONNECTION;
  430.     /* if(cp->data)   free() checks for NULL; smaller code :-) */
  431.     free(cp->data);
  432.     free(cp->ibuf);
  433.     if(cp->flags & CLOSE_SOCK)
  434.         close_s(cp->fd);
  435.     free((char *) cp);
  436. }
  437.   
  438. static void
  439. free_closed_connections()
  440. {
  441.     register struct convection *cp,*p;
  442.     time_t currtime;
  443.   
  444.     currtime = time(&currtime);
  445.   
  446.     for(p = NULLCONNECTION,cp = convections; cp; )
  447.         if(cp->type == CT_CLOSED ||
  448.         cp->type == CT_UNKNOWN && cp->time + 300 < currtime) {
  449.             if(p) {
  450.                 p->next = cp->next;
  451.                 free_connection(cp);
  452.                 cp = p->next;
  453.             } else {
  454.                 convections = cp->next;
  455.                 free_connection(cp);
  456.                 cp = convections;
  457.             }
  458.         } else {
  459.             p = cp;
  460.             cp = cp->next;
  461.         }
  462. }
  463.   
  464. static void
  465. update_permlinks(name,cp)
  466. char *name;
  467. struct convection *cp;
  468. {
  469.     register struct permlink *p;
  470.     time_t currtime;
  471.   
  472.     for(p = permlinks; p; p = p->next)
  473.         if(!strcmp(p->name,name)) {
  474.             currtime = time(&currtime);
  475.             p->convection = cp;
  476.             p->statetime = currtime;
  477.             p->tries = 0;
  478.             p->waittime = 60;
  479.             p->retrytime = currtime + p->waittime;
  480.         }
  481. }
  482.   
  483. static struct convection *
  484. alloc_connection(fd)
  485. int  fd;
  486. {
  487.     register struct convection *cp;
  488.     time_t currtime;
  489.   
  490.     currtime = time(NULL);
  491.   
  492.     cp = (struct convection *)callocw(1,sizeof(struct convection ));
  493.     cp->ibuf = (char *)callocw(1,LINELEN);
  494.     cp->fd = fd;
  495.     cp->maxq = UMaxQ;       /* Maximum qlimit for user */
  496.     cp->flags = CLOSE_SOCK+USE_SOUND;       /* close on exit, by default */
  497.     cp->time = currtime;
  498.     cp->next = convections;
  499.     convections = cp;
  500.     return cp;
  501. }
  502.   
  503. #ifdef LINK
  504. /* check the host links for backlogged data.
  505.  * If larger then set threshold, kill the link.
  506.  * WG7J, 930208
  507.  */
  508. void check_buffer_overload(void) {
  509.     struct convection *p;
  510.   
  511.     /* check the size of the outstanding data buffers */
  512.     for(p = convections; p; p = p->next)
  513.         if((p->maxq != 0) && (socklen(p->fd,1) > p->maxq)) {
  514.                 /* notify everyone of this special :-) occasion */
  515.             bye_command(p);
  516.                 /* Blow this one out of the water */
  517.             shutdown(p->fd,2);
  518.             close_s(p->fd);
  519.         }
  520. }
  521.   
  522. void
  523. connect_permlinks(a,b,c)
  524. int a;
  525. void *b;
  526. void *c;
  527. {
  528.     int s;
  529.     register struct permlink *p;
  530.     struct sockaddr_in cport;
  531.     time_t currtime;
  532.   
  533.     for(;;) {
  534.         pause(15000L);
  535.         for(p = permlinks; p; p = p->next) {
  536.             currtime = time(&currtime);
  537.             if(p->convection || p->retrytime > currtime)
  538.                 continue;
  539.             p->tries++;
  540.             p->waittime <<= 1;
  541.             if(p->waittime > CMaxwait)
  542.                 p->waittime = CMaxwait;
  543.             p->retrytime = p->waittime + currtime;
  544.             cport.sin_family = AF_INET;
  545.             cport.sin_port = IPPORT_CONVERS;
  546.             cport.sin_addr.s_addr = p->addr; /* we've resolved this earlier */
  547.             if((s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  548.                 continue;
  549.             if(connect(s,(char *)&cport,SOCKSIZE) == -1) {
  550.                 shutdown(s,2);  /* to make sure it doesn't linger around */
  551.                 close_s(s);     /* WG7J - 9207228 */
  552.                 continue;
  553.             }
  554.             p->fd = s;
  555.             if(newproc("permlink",CDAEMONSTACK,conv_incom,s,(void *)TELNET,NULL,0) == NULLPROC){
  556.                 shutdown(s,2);  /* blow it out of the water :-) */
  557.                 close_s(s);
  558.             }
  559.         }
  560.         /* This is now called from the garbage collect process, such that it
  561.          * checks even when the linker process isn't running! - WG7J
  562.         check_buffer_overload();
  563.         */
  564.     }
  565. }
  566. #endif
  567.   
  568.   
  569. static void
  570. clear_locks()
  571. {
  572.     register struct convection *p;
  573.   
  574.     for(p = convections;p;p = p->next)
  575.         p->locked = 0;
  576. }
  577.   
  578. static void send_sounds(struct convection *p) {
  579.     if(p->flags & USE_SOUND)
  580.         p->xmitted += usputs(p->fd,"");
  581. }
  582.   
  583. static void
  584. send_user_change_msg(name,host,oldchannel,newchannel)
  585. char  *name,*host;
  586. int  oldchannel,newchannel;
  587. {
  588.     register struct convection *p;
  589.   
  590.     for(p = convections; p; p = p->next) {
  591.         if(p->type == CT_USER && !p->via && !p->locked) {
  592.             if(p->channel == oldchannel) {
  593.                 if(newchannel >= 0) {
  594.                     p->xmitted += usprintf(p->fd,
  595.                     "*** %s switched to channel %d.\n",
  596.                     name,newchannel);
  597.                 } else
  598.                     p->xmitted += usprintf(p->fd,
  599.                     "*** %s signed off.\n",name);
  600.                 p->locked = 1;
  601.             }
  602.             if(p->channel == newchannel) {
  603.                 send_sounds(p);
  604.                 p->xmitted += usprintf(p->fd,
  605.                 "*** %s signed on.\n",name);
  606.                 p->locked = 1;
  607.             }
  608.         }
  609.         if(p->type == CT_HOST && !p->locked) {
  610.             p->xmitted += usprintf(p->fd,
  611.             "/\377\200USER %s %s %d %d %d\n",
  612.             name,host,0,oldchannel,newchannel);
  613.             p->locked = 1;
  614.         }
  615.     }
  616.     return;
  617. }
  618.   
  619. #ifdef Oldcode
  620.   
  621. static char *
  622. formatline(prefix,text)
  623. char  *prefix,*text;
  624. {
  625.   
  626. #define PREFIXLEN 10
  627. #define CONVLINELEN   79
  628.   
  629.     register char  *f,*t,*x;
  630.     register int  l,lw;
  631.   
  632.     static char buf[2*LINELEN];
  633.   
  634.     for(f = prefix,t = buf; *f; *t++ = *f++) ;
  635.     l = (int)(t - buf);
  636.     f = text;
  637.   
  638.     for(;;) {
  639.         while(isspace(uchar(*f)))
  640.             f++;
  641.         if(!*f) {
  642.             *t++ = '\n';
  643.             *t = '\0';
  644.             return buf;
  645.         }
  646.         for(x = f; *x && !isspace(uchar(*x)); x++) ;
  647.         lw = (int)(x - f);
  648.         if(l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
  649.             *t++ = '\n';
  650.             l = 0;
  651.         }
  652.         do {
  653.             *t++ = ' ';
  654.             l++;
  655.         } while(l < PREFIXLEN);
  656.         while(lw--) {
  657.             *t++ = *f++;
  658.             l++;
  659.         }
  660.     }
  661. }
  662.   
  663. static void
  664. send_msg_to_user(fromname,toname,text)
  665. char  *fromname,*toname,*text;
  666. {
  667.     register struct convection *p;
  668.     char buffer[2*LINELEN];
  669.   
  670.     for(p = convections; p; p = p->next) {
  671.         if(p->type == CT_USER && !strcmp(p->name,toname))
  672.             if(p->via) {
  673.                 if(!p->via->locked) {
  674.                     p->via->xmitted += usprintf(p->via->fd,
  675.                     "/\377\200UMSG %s %s %s\n",fromname,toname,text);
  676.                     p->via->locked = 1;
  677.                 }
  678.             } else {
  679.                 if(!p->locked) {
  680.                     if(strcmp(fromname,"conversd")) {
  681.                         sprintf(buffer,"<*%s*>:",fromname);
  682.                         p->xmitted += usputs(p->fd,formatline(buffer,text));
  683.                     } else {
  684.                         p->xmitted += usputs(p->fd,text);
  685.                         p->xmitted += usputc('\n');
  686.                     }
  687.                     p->locked = 1;
  688.                 }
  689.             }
  690.     }
  691.     return;
  692. }
  693.   
  694. static void
  695. send_msg_to_channel(fromname,channel,text)
  696. char  *fromname;
  697. int  channel;
  698. char  *text;
  699. {
  700.     char  buffer[3*LINELEN];
  701.     register struct convection *p;
  702.   
  703.     for(p = convections; p; p = p->next) {
  704.         if(p->type == CT_USER && p->channel == channel)
  705.             if(p->via) {
  706.                 if(!p->via->locked) {
  707.                     p->via->xmitted += usprintf(p->via->fd,
  708.                     "/\377\200CMSG %s %d %s\n",fromname,channel,text);
  709.                     p->via->locked = 1;
  710.                 }
  711.             } else {
  712.                 if(!p->locked) {
  713.                     sprintf(buffer,"<%s>:",fromname);
  714.                     p->xmitted += usputs(p->fd,formatline(&buffer[0],text));
  715.                     p->locked = 1;
  716.                 }
  717.             }
  718.     }
  719. }
  720.   
  721. #else /* Oldcode */
  722.   
  723. /* Returns a formatted version of the given text.
  724.  * The prefix appears at the beginning of the text, and each
  725.  * line after the first will be indented to column PREFIXLEN.
  726.  * All whitespace (SPACE and TAB) will be replaced by a single
  727.  * SPACE character,
  728.  * Lines will be filled to be CONVLINELEN characters long, wrapping
  729.  * words as necessary.
  730.  *
  731.  * This uses an static internal  buffer rather than one passed by
  732.  * the caller.  This increases the static memory used by the program
  733.  * even if converse isn't active.  If we passed a buffer  allocated
  734.  * on the stack, the process's stack would have to be large enough.
  735.  */
  736. static char *
  737. formatline(prefix, text)
  738. char  *prefix, *text;
  739. {
  740.   
  741. #   define PREFIXLEN    10
  742. #   define CONVLINELEN  79
  743. #   define FMTBUFLEN    LINELEN
  744.   
  745.     static char          buf[FMTBUFLEN];
  746.     register char       *f, *t;
  747.     register int         l, lw;
  748.     register int         left = FMTBUFLEN-2;
  749.     /* Runs of characters in delims[] will be collapsed into a single
  750.        space by formatline().
  751.      */
  752.     char                *delims = " \t\n\r";
  753. /*
  754. #   define BPUTC(c)     if (left > 0) { left--; *t++ = (c); } else
  755. */
  756. #   define BPUTC(c)     do{ if (left > 0) { left--; *t++ = (c); }} while(0)
  757.   
  758.     /* Copy prefix into buf; set l to length of prefix.
  759.      */
  760.     l = 0;
  761.     for (f = prefix, t = buf; *f; ) {
  762.         BPUTC (*f++);
  763.         l++;
  764.     }
  765.   
  766.     f = text;
  767.   
  768.     for (;;) {
  769.         /* Skip leading spaces */
  770.         while (isspace(uchar(*f)))
  771.             f++;
  772.   
  773.         /* Return if nothing more or no room left */
  774.         if (!*f || (left <= 0)) {
  775.             *t++ = '\n';        /* don't use BPUTC; do even if !left */
  776.             *t   = '\0';
  777.             return buf;
  778.         }
  779.   
  780.         /* Find length of next word (seq. of non-blanks) */
  781.         lw = strcspn (f, delims);
  782.   
  783.         /* If the word would extend past end of line, do newline */
  784.         if (l > PREFIXLEN && (l + 1 + lw) > CONVLINELEN) {
  785.             BPUTC ('\n');
  786.             l = 0;
  787.         }
  788.   
  789.         /* Put out a single space */
  790.         do {
  791.             BPUTC (' ');
  792.             l++;
  793.         } while(l < PREFIXLEN);
  794.   
  795.         /* Put out the word */
  796.         while(lw--) {
  797.             BPUTC (*f++);
  798.             l++;
  799.         }
  800.     }
  801. #   undef BPUTC
  802. }
  803.   
  804.   
  805. static void
  806. send_msg_to_user(fromname,toname,text)
  807. char  *fromname,*toname,*text;
  808. {
  809.     register struct convection *p;
  810.   
  811.     for (p = convections; p; p = p->next) {
  812.         if(p->type == CT_USER && !strcmp(p->name,toname))
  813.             if(p->via) {
  814.                 if(!p->via->locked) {
  815.                     p->via->xmitted += usprintf(p->via->fd,
  816.                     "/\377\200UMSG %.10s %.10s %.220s\n",
  817.                     fromname, toname, text);
  818.                     p->via->locked = 1;
  819.                 }
  820.             } else {
  821.                 if(!p->locked) {
  822.                     if(strcmp(fromname,"conversd")) {
  823.                         char prefix[NAMELEN+10];
  824.                         char *buf;
  825.   
  826.                         sprintf(prefix,"<*%.10s*>:",fromname);
  827.   
  828.                         buf = formatline (prefix,text);
  829.                         p->xmitted += strlen (buf);
  830.                         (void) usputs (p->fd, buf);
  831.                     } else {    /* not from conversd */
  832.                         p->xmitted += strlen (text);
  833.                         (void) usputs (p->fd, text);
  834.                     }   /* not from conversd */
  835.                     p->locked = 1;
  836.                 } /* if not locked */
  837.             }   /* not via */
  838.     } /* for */
  839. }
  840.   
  841. static void
  842. send_msg_to_channel(fromname,channel,text)
  843. char  *fromname;
  844. int  channel;
  845. char  *text;
  846. {
  847.     register struct convection *p;
  848.   
  849.     for (p = convections; p; p = p->next) {
  850.         if(p->type == CT_USER && p->channel == channel)
  851.             if(p->via) {
  852.                 if(!p->via->locked) {
  853.                     p->via->xmitted += usprintf(p->via->fd,
  854.                     "/\377\200CMSG %.10s %d %.220s\n",
  855.                     fromname, channel, text);
  856.                     p->via->locked = 1;
  857.                 }
  858.             } else {
  859.                 if(!p->locked) {
  860.                     char         prefix[NAMELEN+10];
  861.                     char        *buf;
  862.   
  863.                     sprintf(prefix,"<%.10s>:", fromname);
  864.   
  865.                     buf = formatline (prefix, text);
  866.                     p->xmitted += strlen (buf);
  867.                     (void) usputs (p->fd, buf);
  868.   
  869.                     p->locked = 1;
  870.                 } /* not locked */
  871.             } /* not via */
  872.     } /* for */
  873. }
  874.   
  875.   
  876. #endif /* Oldcode */
  877.   
  878.   
  879. extern char *Months[];      /* in smtpserv.c */
  880.   
  881. static char  *
  882. timestring(gmt)
  883. long  gmt;
  884. {
  885.     static char  buffer[10];
  886.     struct tm *tm;
  887.     time_t currtime;
  888.   
  889.     time(&currtime);
  890.     tm = localtime(&gmt);
  891.     if(gmt + 24 * 60 * 60 > currtime)
  892.         sprintf(buffer," %2d:%02d",tm->tm_hour,tm->tm_min);
  893.     else
  894.         sprintf(buffer,"%-3.3s %2d",Months[tm->tm_mon],tm->tm_mday);
  895.     return buffer;
  896. }
  897.   
  898. #ifdef space
  899. char invitetext[] = "\n*** Message from %s at%s ...\nPlease join convers channel %d.\n\n";
  900. char mbinvitetext[] = "\n*** Message from %s at%s ...\nPlease join convers by typing 'CONV %d' !\n\n";
  901. char responsetext[] = "*** Invitation sent to %s @ %s";
  902. #else
  903. char invitetext[] = "\n*** Msg frm %s at%s ...\nPse join ch. %d.\n\n";
  904. char mbinvitetext[] = "\n*** Msg frm %s at%s ...\nPse hit 'CONV %d' to join convers.\n\n";
  905. char responsetext[] = "*** sent to %s @ %s";
  906. #endif
  907. char cnvd[] = "conversd";
  908.   
  909. static void
  910. send_invite_msg(fromname,toname,channel)
  911. char  *fromname,*toname;
  912. int  channel;
  913. {
  914.   
  915.     char buffer[LINELEN];
  916.     struct convection *p;
  917. #ifdef MAILBOX
  918.     struct mbx *m;
  919. #endif
  920.     time_t currtime;
  921.   
  922.     currtime = time(&currtime);
  923.   
  924. #ifdef MAILBOX
  925.     /* Check users in the mailbox that aren't active */
  926.     for(m=Mbox;m;m=m->next){
  927.         if(m->state == MBX_CMD && !stricmp(m->name,toname)) {
  928.             usprintf(m->user,mbinvitetext,fromname,timestring(currtime),channel);
  929.             usflush(m->user);
  930.             clear_locks();
  931.             sprintf(buffer,responsetext,toname,"BBS@");
  932.             strcat(buffer,Hostname);
  933.             send_msg_to_user(cnvd,fromname,buffer);
  934.             return;
  935.         }
  936.     }
  937. #endif
  938.   
  939.     /* check the current convers users */
  940.     for(p = convections; p; p = p->next) {
  941.         if(p->type == CT_USER && !stricmp(p->name,toname)) {
  942.             if(p->channel == channel) {
  943.                 clear_locks();
  944.                 sprintf(buffer,"*** User %s is already on this channel.\n",toname);
  945.                 send_msg_to_user(cnvd,fromname,buffer);
  946.                 return;
  947.             }
  948.             if(!p->via && !p->locked) {
  949.                 p->xmitted += usprintf(p->fd,invitetext,fromname, \
  950.                 timestring(currtime),channel);
  951.                 clear_locks();
  952.                 sprintf(buffer,responsetext,toname,Chostname);
  953.                 send_msg_to_user(cnvd,fromname,buffer);
  954.                 return;
  955.             }
  956.             if(p->via && !p->via->locked) {
  957.                 p->via->xmitted += usprintf(p->via->fd,
  958.                 "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  959.                 return;
  960.             }
  961.         }
  962.     }
  963.     /* Nothing found locally, invite user on all links */
  964.     for(p = convections; p; p = p->next) {
  965.         if(p->type == CT_HOST && !p->locked) {
  966.             p->xmitted += usprintf(p->fd,
  967.             "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  968.         }
  969.     }
  970.     return;
  971. }
  972.   
  973. static void
  974. bye_command(cp)
  975. struct convection *cp;
  976. {
  977.     struct convection *p;
  978.   
  979.     switch(cp->type) {
  980.         case CT_UNKNOWN:
  981.             cp->type = CT_CLOSED;
  982.             break;
  983.         case CT_USER:
  984.             cp->type = CT_CLOSED;
  985.             clear_locks();
  986.             send_user_change_msg(cp->name,cp->host,cp->channel,-1);
  987.             ConvUsers--;
  988.             break;
  989.         case CT_HOST:
  990.             cp->type = CT_CLOSED;
  991.             update_permlinks(cp->name,NULLCONNECTION);
  992.             for(p = convections; p; p = p->next)
  993.                 if(p->via == cp) {
  994.                     p->type = CT_CLOSED;
  995.                     clear_locks();
  996.                     send_user_change_msg(p->name,p->host,p->channel,-1);
  997.                 }
  998.             ConvHosts--;
  999.             break;
  1000.         case CT_CLOSED:
  1001.             break;
  1002.     }
  1003. }
  1004.   
  1005. static void
  1006. channel_command(cp)
  1007. struct convection *cp;
  1008. {
  1009.     char  s[7];
  1010.     int  newchannel;
  1011.   
  1012.     s[0] = '\0';
  1013.     sscanf(cp->ibuf,"%*s %6s",s);
  1014.     if(s[0] == '\0') {
  1015. #ifdef space
  1016.         cp->xmitted += usprintf(cp->fd,"*** You are on channel %d.\n",cp->channel);
  1017. #else
  1018.         cp->xmitted += usprintf(cp->fd,"* On channel %d.\n",cp->channel);
  1019. #endif
  1020.         return;
  1021.     }
  1022.     newchannel = atoi(s);
  1023.     if(newchannel < 0) {
  1024.         /*  || newchannel > MAXCHANNEL) { */
  1025.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1026.         return;
  1027.     }
  1028.     if(newchannel == cp->channel) {
  1029.         cp->xmitted += usprintf(cp->fd,
  1030.         "*** Already on channel %d.\n",cp->channel);
  1031.         return;
  1032.     }
  1033.     send_user_change_msg(cp->name,cp->host,cp->channel,newchannel);
  1034.     cp->channel = newchannel;
  1035.     cp->xmitted += usprintf(cp->fd,"*** Now on channel %d.\n",cp->channel);
  1036.     return;
  1037. }
  1038.   
  1039. static void
  1040. help_command(cp)
  1041. struct convection *cp;
  1042. {
  1043. #ifdef space
  1044.     cp->xmitted += usputs(cp->fd,"Commands may be abbreviated. Commands are:\n");
  1045.     cp->xmitted += usputs(cp->fd,"/? or /HELP     Print help information\n");
  1046.     cp->xmitted += usputs(cp->fd,"/BYE            Terminate the convers session\n");
  1047.     cp->xmitted += usputs(cp->fd,"/CHANNEL        Switch to channel n\n");
  1048.     cp->xmitted += usputs(cp->fd,"/EXIT           Terminate the convers session\n");
  1049.     cp->xmitted += usputs(cp->fd,"/INV user       Invite user to join your channel\n");
  1050.     cp->xmitted += usputs(cp->fd,"/LINKS [L]      List all connections to other hosts\n");
  1051.     cp->xmitted += usputs(cp->fd,"/MSG user text  Send a private message to user\n");
  1052.     cp->xmitted += usputs(cp->fd,"/PERSONAL text  Set or show some personal text\n");
  1053.     cp->xmitted += usputs(cp->fd,"/QUIT           Terminate the convers session\n");
  1054.     cp->xmitted += usputs(cp->fd,"/SOUNDS y|n     Turn bell on or off\n");
  1055.     cp->xmitted += usputs(cp->fd,"/WHO [QUICK]    List all users and their channel numbers\n");
  1056.     cp->xmitted += usputs(cp->fd,"/WR user text   Send a private message to user\n"
  1057.     "***\n");
  1058. #else
  1059.     cp->xmitted += usputs(cp->fd,"no help\n");
  1060. #endif
  1061.     return;
  1062. }
  1063.   
  1064. static void
  1065. version_command(cp)
  1066. struct convection *cp;
  1067. {
  1068.     usprintf(cp->fd,"%s Convers Server.\n",shortversion);
  1069. }
  1070.   
  1071. static void
  1072. invite_command(cp)
  1073. struct convection *cp;
  1074. {
  1075.     char toname[NAMELEN+1];
  1076.     char *cp1;
  1077.   
  1078.     toname[0] = '\0';
  1079.     sscanf(cp->ibuf,"%*s %10s",toname);
  1080.     if((cp1=strchr(toname,'@')) != NULLCHAR)
  1081.         *cp1 = '\0';
  1082.     if(toname[0] != '\0')
  1083.         send_invite_msg(cp->name,toname,cp->channel);
  1084.     return;
  1085. }
  1086.   
  1087. int ShowConfLinks(int s, int full) {
  1088.     int num;
  1089.     struct convection *pc;
  1090.     struct permlink *pp;
  1091.     char  tmp[20];
  1092.   
  1093.     num = usprintf(s,"Host       State         Since%s\n",
  1094.     (full) ? " NextTry Tries Receivd Xmitted" : "");
  1095.     for(pc = convections; pc; pc = pc->next)
  1096.         if(pc->type == CT_HOST)
  1097.             num += usprintf(s,
  1098.             (full) ?
  1099.             "%-10s Connected    %s               %7lu %7lu\n" :
  1100.             "%-10s Connected    %s\n",
  1101.             pc->name,
  1102.             timestring(pc->time),
  1103.             pc->received,
  1104.             pc->xmitted);
  1105.   
  1106.     for(pp = permlinks; pp; pp = pp->next)
  1107.         if(!pp->convection || pp->convection->type != CT_HOST) {
  1108.             strcpy(tmp,timestring(pp->retrytime));
  1109.             num += usprintf(s,
  1110.             (full) ?
  1111.             "%-10s %-12s %s %s %5d\n" :
  1112.             "%-10s %-12s %s\n",
  1113.             pp->name,
  1114.             pp->convection ? "Connecting" : "Disconnected",
  1115.             timestring(pp->statetime),
  1116.             tmp,
  1117.             pp->tries);
  1118.         }
  1119.     num += usputs(s,"***\n");
  1120.     return num;
  1121. }
  1122.   
  1123. static void
  1124. links_command(cp)
  1125. struct convection *cp;
  1126. {
  1127.     char full[3];
  1128.     int f = 0;
  1129.   
  1130.     full[0] = '\0';
  1131.     sscanf(cp->ibuf,"%*s %2s",full);
  1132.     if(*full == 'l' || *full == 'L')
  1133.         f = 1;
  1134.     cp->xmitted += ShowConfLinks(cp->fd,f);
  1135.     return;
  1136. }
  1137.   
  1138. static void
  1139. msg_command(cp)
  1140. struct convection *cp;
  1141. {
  1142.   
  1143.     char dummy[LINELEN],toname[NAMELEN+1],*text;
  1144.     register struct convection *p;
  1145.   
  1146.     toname[0] = '\0';
  1147.     sscanf(cp->ibuf,"%s %10s",dummy,toname);
  1148.     text = &cp->ibuf[0];
  1149.     text += strlen(dummy) + strlen(toname) + 2;
  1150.   
  1151.     if(!*text)
  1152.         return;
  1153.     for(p = convections; p; p = p->next)
  1154.         if(p->type == CT_USER && !strcmp(p->name,toname))
  1155.             break;
  1156.     if(!p)
  1157.         cp->xmitted += usprintf(cp->fd,"*** No such user: %s.\n",toname);
  1158.     else
  1159.         send_msg_to_user(cp->name,toname,text);
  1160.     return;
  1161. }
  1162.   
  1163. /* Set some personal data, like name and qth - WG7J */
  1164. #define PERSONAL_LEN 31
  1165.   
  1166. static void
  1167. personal_command(cp)
  1168. struct convection *cp;
  1169. {
  1170.     struct convection *p;
  1171.     char *cp2;
  1172.   
  1173.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1174.         cp2++;
  1175.         if(*cp2) {  /* there actually is an argument */
  1176.             if(cp->data)
  1177.                 free(cp->data);
  1178.             rip(cp->ibuf);      /* get rid of ending '\n' */
  1179.             if(strlen(cp2) > PERSONAL_LEN)
  1180.                 *(cp2+PERSONAL_LEN) = '\0';
  1181.             cp->data = strdup(cp2);
  1182.             /* update all links too ! - WG7J */
  1183.             for(p=convections;p;p=p->next)
  1184.                 if(p->type == CT_HOST)
  1185.                     p->xmitted += usprintf(p->fd,"/\377\200UDAT %s %s %s\n",
  1186.                     cp->name,cp->host,cp->data);
  1187.             return;
  1188.         }
  1189.     }
  1190.     cp->xmitted += usprintf(cp->fd,"*** data set to: %s\n", \
  1191.     cp->data ? cp->data : "" );
  1192.     return;
  1193. }
  1194.   
  1195. /* find the personal information for this user */
  1196. void set_personal(struct convection *cp) {
  1197.     FILE *fp;
  1198.     char *cp1;
  1199.   
  1200.     if((fp = fopen(Cinfo,"r")) == NULL)
  1201.         return;
  1202.     while(fgets(cp->ibuf,LINELEN,fp) != NULL) {
  1203.         cp1 = cp->ibuf;
  1204.         /* find end of name */
  1205.         while(*cp1 != ' ' && *cp1 != '\t' && *cp1 != '\0')
  1206.             cp1++;
  1207.         if(!*cp1)
  1208.             continue;
  1209.         *cp1 = '\0';
  1210.         if(stricmp(cp->name,cp->ibuf))
  1211.             continue;
  1212.         /* Found personal data ! */
  1213.         *cp1 = ' ';
  1214.         fclose(fp);
  1215.         personal_command(cp);
  1216.         return;
  1217.     }
  1218.     fclose(fp);
  1219. }
  1220.   
  1221. void SendMotd(int s) {
  1222.     FILE *fp;
  1223.   
  1224.     if((fp=fopen(ConvMotd,"r")) != NULL) {
  1225.         sendfile(fp, s, ASCII_TYPE, 0, NULL);
  1226.         fclose(fp);
  1227.     }
  1228. }
  1229.   
  1230. /* protected by ftpusers file - WG7J */
  1231. static void
  1232. name_command(cp)
  1233. struct convection *cp;
  1234. {
  1235.     int newchannel = CDefaultChannel;
  1236.     char dummy[7];
  1237.     char *path;
  1238.     int pwdignore;
  1239.     long privs;
  1240.   
  1241.     cp->name[0] = '\0';
  1242.     dummy[0] = '\0';
  1243.     sscanf(cp->ibuf,"%*s %10s %6s",cp->name,dummy);
  1244.     if(dummy[0] != '\0')
  1245.         newchannel = atoi(dummy);
  1246.     if(cp->name[0] == '\0')
  1247.         return;
  1248.     /* now check with ftpusers file - WG7J */
  1249.     if((path = mallocw(MBXLINE)) == NULLCHAR)
  1250.         return;
  1251.     pwdignore = 1;
  1252.     privs = userlogin(cp->name,NULLCHAR,&path,MBXLINE,&pwdignore);
  1253.     free(path);
  1254.     if(privs & NO_CONVERS)
  1255.         return;
  1256.     strlwr(cp->name);
  1257.     strcpy(cp->host,Chostname);
  1258.     cp->type = CT_USER;
  1259.     cp->xmitted += usprintf(cp->fd,
  1260.     "Conference @ %s  Type /HELP for help.\n",Chostname);
  1261.     /* Send the motd */
  1262.     SendMotd(cp->fd);
  1263.     if(dummy[0] != '\0' && newchannel < 0) {
  1264.         /* || newchannel > MAXCHANNEL) { */
  1265.         cp->xmitted += usprintf(cp->fd,cnumber,MAXCHANNEL);
  1266.     } else
  1267.         cp->channel = newchannel;
  1268.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  1269.     set_personal(cp);
  1270.     ConvUsers++;
  1271.     return;
  1272. }
  1273.   
  1274. /* Set or show the status of the 'sound' flag - WG7J */
  1275. static void
  1276. sounds_command(cp)
  1277. struct convection *cp;
  1278. {
  1279.     char *cp2;
  1280.   
  1281.     if((cp2 = strchr(cp->ibuf,' ')) != NULLCHAR) {
  1282.         cp2++;
  1283.         if(*cp2) {   /* There is an argument */
  1284.             if(*cp2 == 'n' || *cp2 == 'N') {   /* Turn it off */
  1285.                 cp->flags &= ~USE_SOUND;
  1286.             } else
  1287.                 cp->flags |= USE_SOUND;
  1288.             return;
  1289.         }
  1290.     }
  1291.     if(cp->flags & USE_SOUND)
  1292.         usputs(cp->fd,"*** Sounds on\n");
  1293.     else
  1294.         usputs(cp->fd,"*** Sounds off\n");
  1295.     return;
  1296. }
  1297.   
  1298. /* Print a user display, return the number of characters sent */
  1299. int ShowConfUsers(int s,int quick,char *name) {
  1300.     int num,channel;
  1301.     struct convection *p;
  1302. #ifdef MAILBOX
  1303.     struct mbx *m;
  1304. #endif
  1305.     char buffer[LINELEN];
  1306.   
  1307.     if(quick) {
  1308.         num = usputs(s,"Channel Users\n");
  1309.         clear_locks();
  1310.         do {
  1311.             channel = -1;
  1312.             for(p = convections; p; p = p->next) {
  1313.                 if(p->type == CT_USER &&
  1314.                     !p->locked &&
  1315.                 (channel < 0 || channel == p->channel)) {
  1316.                     if(channel < 0) {
  1317.                         channel = p->channel;
  1318.                         sprintf(buffer,"%7d",channel);
  1319.                     }
  1320.                     strcat(buffer," ");
  1321.                     strcat(buffer,p->name);
  1322.                     p->locked = 1;
  1323.                 }
  1324.             }
  1325.             if(channel >= 0) {
  1326.                 num += usputs(s,buffer);
  1327.                 num += usputc(s,'\n');
  1328.             }
  1329.         } while(channel >= 0);
  1330.     } else {
  1331.         num = usputs(s,"User       Host       Via        Channel   Time Personal\n");
  1332.         for(p = convections; p; p = p->next) {
  1333.             if(p->type == CT_USER) {
  1334.                 if(name == NULL || *name == '\0' || !stricmp(p->name,name))
  1335.                     num += usprintf(s,"%-10s %-10s %-10s %7d %s %s\n",
  1336.                     p->name,
  1337.                     p->host,
  1338.                     p->via ? p->via->name : "",
  1339.                     p->channel,
  1340.                     timestring(p->time),
  1341.                     p->data ? p->data : "" );
  1342.             }
  1343.         }
  1344.     }
  1345. #ifdef MAILBOX
  1346.     for(m=Mbox;m;m=m->next) {
  1347.         if(m->state == MBX_CMD) {
  1348.             if(quick)
  1349.                 num += usprintf(s," BBS %s\n",m->name);
  1350.             else
  1351.                 num += usprintf(s,"%-10s BBS@%s\n",m->name,Hostname);
  1352.         }
  1353.     }
  1354. #endif
  1355.     num += usputs(s,"***\n");
  1356.     return num;
  1357. }
  1358.   
  1359. static void
  1360. who_command(cp)
  1361. struct convection *cp;
  1362. {
  1363.     char buffer[LINELEN];
  1364.     int quick = 0;
  1365.   
  1366.     buffer[0] = '\0';
  1367.     sscanf(cp->ibuf,"%*s %s",buffer);
  1368.     if(buffer[0] == 'q')
  1369.         quick = 1;
  1370.     cp->xmitted += ShowConfUsers(cp->fd,quick,buffer);
  1371.     return;
  1372. }
  1373.   
  1374. static void
  1375. h_cmsg_command(cp)
  1376. struct convection *cp;
  1377. {
  1378.     char *text;
  1379.     int  channel;
  1380.     char name[LINELEN],dummy[40];
  1381.   
  1382.     sscanf(cp->ibuf,"%s %10s %d",dummy,name,&channel);
  1383.     text = &cp->ibuf[0];
  1384.     text += strlen(dummy) + strlen(name) + 2;
  1385.     while(isspace(*text) == 0)
  1386.         text++;
  1387.     text++;
  1388.     if(isprint(*text) != 0)
  1389.         send_msg_to_channel(name,channel,text);
  1390.     return;
  1391. }
  1392.   
  1393. /* Return 1 if the host is to be allowed, or 0 if refused - WG7J */
  1394. int Allow_host(int s) {
  1395.     struct filter_link *fl;
  1396.     struct sockaddr_in fsocket;
  1397.     int i = sizeof(struct sockaddr_in);
  1398.   
  1399.     if(Filterlinks) {    /* Check for this ip address */
  1400.         getpeername(s,(char *)&fsocket,&i);
  1401.         for(fl=Filterlinks;fl;fl=fl->next)
  1402.             if(fl->addr == fsocket.sin_addr.s_addr)
  1403.                 return FilterMode;
  1404.         /* Not found ! */
  1405.         return !FilterMode;
  1406.     }
  1407.     return 1;
  1408. }
  1409.   
  1410. static void
  1411. h_host_command(cp)
  1412. struct convection *cp;
  1413. {
  1414.   
  1415.     char name[NAMELEN+1];
  1416.     struct convection *p;
  1417.     struct permlink *pp;
  1418.   
  1419.     if(!Allow_host(cp->fd)) {
  1420.         bye_command(cp);
  1421.         return;
  1422.     }
  1423.     name[0] = '\0';
  1424.     sscanf(cp->ibuf,"%*s %10s",name);
  1425.     if(name[0] == '\0') {
  1426.         bye_command(cp);
  1427.         return;
  1428.     }
  1429.     for(p = convections; p; p = p->next)
  1430.         if(!strcmp(p->name,name)) {
  1431.             bye_command(p);
  1432.             return;
  1433.         }
  1434.     for(pp = permlinks; pp; pp = pp->next)
  1435.         if(!strcmp(pp->name,name) && pp->convection && pp->convection != cp) {
  1436.             bye_command((strcmp(Chostname,name) < 0) ? pp->convection : cp);
  1437.             return;
  1438.         }
  1439. /*
  1440.     if(cp->type != CT_UNKNOWN)
  1441.         return;
  1442.  */
  1443.     cp->type = CT_HOST;
  1444.     cp->maxq = HMaxQ;
  1445.     strcpy(cp->name,name);      /* already allocated */
  1446.     update_permlinks(name,cp);
  1447.     cp->xmitted += usprintf(cp->fd,"/\377\200HOST %s\n",Chostname);
  1448.     for(p = convections; p; p = p->next)
  1449.         if(p->type == CT_USER) {
  1450.             cp->xmitted += usprintf(cp->fd,
  1451.             "/\377\200USER %s %s %d %d %d\n",
  1452.             p->name,p->host,0,-1,p->channel);
  1453.             if(p->data)
  1454.                 cp->xmitted += usprintf(cp->fd,
  1455.                 "/\377\200UDAT %s %s %s\n",
  1456.                 p->name,p->host,p->data);
  1457.         }
  1458.     ConvHosts++;
  1459.     return;
  1460. }
  1461.   
  1462. static void
  1463. h_invi_command(cp)
  1464. struct convection *cp;
  1465. {
  1466.     char fromname[NAMELEN+1],toname[NAMELEN+1];
  1467.     int  channel;
  1468.   
  1469.     sscanf(cp->ibuf,"%*s %10s %10s %d",fromname,toname,&channel);
  1470.     send_invite_msg(fromname,toname,channel);
  1471.     return;
  1472. }
  1473.   
  1474. static void
  1475. h_loop_command(cp)
  1476. struct convection *cp;
  1477. {
  1478.     char host[NAMELEN+1];
  1479.   
  1480.     sscanf(cp->ibuf,"%*s %10s",host);
  1481.     log(cp->fd, "conversd rx: LOOP %s",host);
  1482.     bye_command(cp);
  1483. }
  1484.   
  1485. /* Command to take user's personal data across a link - WG7J */
  1486. void
  1487. h_udat_command(cp)
  1488. struct convection *cp;
  1489. {
  1490.     char *name,*host,*data;
  1491.     int len;
  1492.     struct convection *p;
  1493.   
  1494.     /* do a validity check first */
  1495.     if((name = strchr(cp->ibuf,' ')) == NULLCHAR)
  1496.         return;
  1497.     name++;
  1498.     if((host = strchr(name,' ')) == NULLCHAR)
  1499.         return;
  1500.     *host++ = '\0';
  1501.     if((data = strchr(host,' ')) == NULLCHAR)
  1502.         return;
  1503.     *data++ = '\0';
  1504.     rip(data);      /* rip the '\n' */
  1505.     if((len=strlen(data)) == 0)
  1506.         return;
  1507.     if(len > PERSONAL_LEN)
  1508.         *(data+PERSONAL_LEN) = '\0';
  1509.   
  1510.     /* everything seems fine, now find user ! */
  1511.     for(p=convections;p;p=p->next) {
  1512.         if(!strcmp(p->name,name) && !strcmp(p->host,host)) {
  1513.             if(p->data)
  1514.                 free(p->data);
  1515.             p->data = strdup(data);
  1516.         }
  1517.         /* update over other links  Apr 12/93 VE3DTE */
  1518.         if(p->type == CT_HOST && !p->locked)
  1519.             p->xmitted += usprintf(p->fd,"/\377\200UDAT %s %s %s\n",
  1520.             name,host,data);
  1521.     }
  1522. }
  1523.   
  1524. static void
  1525. h_umsg_command(cp)
  1526. struct convection *cp;
  1527. {
  1528.     char dummy[NAMELEN+1],fromname[NAMELEN+1],toname[NAMELEN+1],*text;
  1529.   
  1530.     sscanf(cp->ibuf,"%s %10s %10s",dummy,fromname,toname);
  1531.     text = &cp->ibuf[0];
  1532.     text += strlen(dummy) + strlen(fromname) + strlen(toname) + 3;
  1533.     if(*text)
  1534.         send_msg_to_user(fromname,toname,text);
  1535.     return;
  1536. }
  1537.   
  1538. static void
  1539. h_user_command(cp)
  1540. struct convection *cp;
  1541. {
  1542.     char host[3*NAMELEN+1],name[3*NAMELEN+1];
  1543.     int  newchannel,oldchannel;
  1544.     struct convection *p;
  1545.     time_t currtime;
  1546.   
  1547.     currtime = time(&currtime);
  1548.   
  1549.     sscanf(cp->ibuf,"%*s %s %s %*s %d %d",name,host,&oldchannel,&newchannel);
  1550.     /* Make sure the fields are not longer */
  1551.     host[NAMELEN] = name[NAMELEN] = '\0';
  1552.   
  1553.     for(p = convections; p; p = p->next)
  1554.         if(p->type == CT_USER) {
  1555.             /* new 920705 dl9sau */
  1556.             /* If Neighbour2 registers a user on HostX, while someone has already
  1557.              * been registered for HostX via Neighbour1, then we definitely have
  1558.              * a loop !  We send a loop detect message and then close the link:
  1559.              * /..LOOP <Chostname> <myneighbour> <host>
  1560.              *
  1561.              * The LOOP PREVENTION CODE detects ONLY a loop if it starts at this
  1562.              * host. That's, why I suggest this code to be implemented in every
  1563.              * conversd implementation.
  1564.              */
  1565.             if (oldchannel < 0 && p->via != cp && !stricmp(p->host, host)) {
  1566.                 usprintf(cp->fd,"/\377\200LOOP %s %s %s\n", \
  1567.                 Chostname, host,p->via ? p->via->name : Chostname);
  1568.                 log(cp->fd, "conversd sent: LOOP %s",host);
  1569.                 bye_command(cp);
  1570.                 return;
  1571.             }
  1572.             if(p->channel == oldchannel && p->via == cp && \
  1573.                 !strcmp(p->name,name) && !strcmp(p->host,host))
  1574.                 break;
  1575.         }
  1576.     if(!p) {
  1577.         p = (struct convection *)callocw(1,sizeof(struct convection ));
  1578.         p->type = CT_USER;
  1579.         strcpy(p->name,name);
  1580.         strcpy(p->host,host);
  1581.         p->via = cp;
  1582.         p->channel = oldchannel;
  1583.         p->time = currtime;
  1584.         p->next = convections;
  1585.         convections = p;
  1586.     }
  1587.     if((p->channel = newchannel) < 0) {
  1588.         p->type = CT_CLOSED;
  1589.         free_closed_connections();  /*  VE3DTE Apr 5/93 */
  1590.     }
  1591.     send_user_change_msg(name,host,oldchannel,newchannel);
  1592.     return;
  1593. }
  1594.   
  1595. struct cmdtable {
  1596.     char  *name;
  1597.     void (*fnc)(struct convection *);
  1598.     int  states;
  1599. };
  1600. struct cmdtable DFAR cmdtable[] = {
  1601.     "?",        help_command,       CM_USER,
  1602.     "bye",      bye_command,        CM_USER,
  1603.     "channel",  channel_command,    CM_USER,
  1604.     "exit",     bye_command,        CM_USER,
  1605.     "help",     help_command,       CM_USER,
  1606.     "invite",   invite_command,     CM_USER,
  1607.     "links",    links_command,      CM_USER,
  1608.     "msg",      msg_command,        CM_USER,
  1609.     "name",     name_command,       CM_UNKNOWN,
  1610.     "personal", personal_command,   CM_USER,
  1611.     "quit",     bye_command,        CM_USER,
  1612.     "sounds",   sounds_command,     CM_USER,
  1613.     "version",  version_command,    CM_USER,
  1614.     "who",      who_command,        CM_USER,
  1615.     "write",    msg_command,        CM_USER,
  1616.   
  1617.     "\377\200cmsg", h_cmsg_command,     CM_HOST,
  1618.     "\377\200host", h_host_command,     CM_UNKNOWN,
  1619.     "\377\200invi", h_invi_command,     CM_HOST,
  1620.     "\377\200loop", h_loop_command,     CM_HOST,
  1621.     "\377\200udat", h_udat_command,     CM_HOST,
  1622.     "\377\200umsg", h_umsg_command,     CM_HOST,
  1623.     "\377\200user", h_user_command,     CM_HOST,
  1624.     0,      0,          0,
  1625. };
  1626.   
  1627. static void
  1628. process_commands(cp,m)
  1629. struct convection *cp;
  1630. struct mbx *m;
  1631. {
  1632.     char arg[LINELEN];
  1633.     int arglen,size;
  1634.     char *ccp;
  1635.     struct cmdtable *cmdp;
  1636.   
  1637.     for(;;) {
  1638.         loop:
  1639.         if(cp->type == CT_CLOSED)
  1640.             break;
  1641.         setflush(cp->fd,'\n');
  1642.         usflush(cp->fd);
  1643.         memset(cp->ibuf,0,LINELEN);
  1644.         if(cp->type != CT_HOST)
  1645.             alarm(Ctdiscinit * 1000L);
  1646.         if((size = recvline(cp->fd,cp->ibuf,LINELEN-1)) <= 0)
  1647.             break;
  1648.         alarm(0L);
  1649.         cp->received += size;
  1650.         clear_locks();
  1651.         cp->locked = 1;
  1652.         if(*cp->ibuf == '/') {
  1653.             ccp = &cp->ibuf[1];
  1654.             arg[0] = '\0';
  1655.             sscanf(ccp,"%s",arg);
  1656.             arglen = strlen(arg);
  1657.             /* We are about to parse a command; most likely there
  1658.              * is alot of output; try to avoid fragmenting that
  1659.              * data by doing our own flushing ! - WG7J
  1660.              */
  1661.             setflush(cp->fd,-1);
  1662.             for(cmdp = cmdtable; cmdp->name; cmdp++) {
  1663.                 if(!strncmpi(cmdp->name,arg,arglen)) {
  1664.                     if(cmdp->states & (1 << cp->type))
  1665.                         (*cmdp->fnc)(cp);
  1666.                     goto loop;
  1667.                 }
  1668.             }
  1669.             if(cp->type == CT_USER)
  1670.                 cp->xmitted += usprintf(cp->fd,
  1671.                 "*** Unknown command '/%s'. Type /HELP for help.\n",arg);
  1672.             goto loop;
  1673.         }
  1674.         if((ccp = strpbrk(cp->ibuf,"\r\n")) != NULLCHAR)
  1675.             *ccp = '\0';
  1676.         if(isprint(cp->ibuf[0]) != 0 && cp->type == CT_USER)
  1677.             send_msg_to_channel(cp->name,cp->channel,cp->ibuf);
  1678.     }
  1679.     bye_command(cp);
  1680.     sockblock(cp->fd,SOCK_BLOCK);
  1681.     free_closed_connections();
  1682. }
  1683.   
  1684. /* Incoming convers session */
  1685. void
  1686. conv_incom(s,t,p)
  1687. int s;
  1688. void *t;
  1689. void *p;
  1690. {
  1691.     struct convection *cp;
  1692.     struct permlink *pl;
  1693.   
  1694.     sockowner(s,Curproc);   /* We own it now */
  1695.     sockmode(s,SOCK_BINARY);
  1696.     sockblock(s,SOCK_NOTXBLOCK);   /* prevent backlogs ! */
  1697.     cp = alloc_connection(s);
  1698.     cp->channel = CDefaultChannel;
  1699.   
  1700.     for(pl = permlinks; pl; pl = pl->next)
  1701.         if(pl->fd == s) {
  1702.             pl->convection = cp;
  1703.             cp->xmitted += usprintf(s,"/\377\200HOST %s\n",Chostname);
  1704.         }
  1705.   
  1706.     if(pl == NULLPERMLINK) {
  1707. #ifdef AX25
  1708.         if((int)t == AX25TNC) { /* figure out call from socket */
  1709.             struct usock *up;
  1710.             char *chrp;
  1711.   
  1712.             if((up = itop(s)) == NULLUSOCK) {
  1713.                 free_connection(cp);
  1714.                 return;
  1715.             }
  1716.             sockmode(s,SOCK_ASCII);
  1717.             pax25(cp->name,up->cb.ax25->remote);
  1718.             if((chrp=strchr(cp->name,'-')) != NULL)
  1719.                 *chrp = '\0';
  1720.             strlwr(cp->name);
  1721.             strcpy(cp->host,Chostname);
  1722.             cp->type = CT_USER;
  1723.             cp->xmitted += usprintf(s,
  1724.             "Conference @ %s  Type /HELP for help.\n",Chostname);
  1725.             SendMotd(s);
  1726.             clear_locks();
  1727.             cp->locked = 1; /* send to everyone but ourself */
  1728.             send_user_change_msg(cp->name,cp->host,-1,CDefaultChannel);
  1729.             set_personal(cp);
  1730.             ConvUsers++;
  1731.         } else
  1732. #endif
  1733.             usputs(cp->fd,"\npse login with '/n <call>'\n\n");
  1734.     }
  1735.     process_commands(cp,NULLMBX);
  1736. }
  1737.   
  1738. #ifdef MAILBOX
  1739.   
  1740. /* this is for Mailbox users */
  1741. void
  1742. mbox_converse(struct mbx *m,int channel)
  1743. {
  1744.     struct convection *cp;
  1745.     int oldflush;
  1746.   
  1747.     sockblock(m->user,SOCK_NOTXBLOCK);  /* prevent backlogs ! */
  1748.     oldflush = setflush(m->user,'\n');  /* automatic line flushing */
  1749.     cp = alloc_connection(m->user);
  1750.     cp->channel = channel;
  1751.     strcpy(cp->name,m->name);
  1752.     strcpy(cp->host,Chostname);
  1753.     cp->type = CT_USER;
  1754.     cp->flags &= ~CLOSE_SOCK;     /* do not close socket on exit */
  1755.     cp->xmitted += usprintf(m->user,
  1756.     "Conference @ %s  Type /HELP for help.\n",Chostname);
  1757.     SendMotd(m->user);
  1758.     clear_locks();
  1759.     cp->locked = 1; /* send to everyone but ourself */
  1760.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  1761.     set_personal(cp);
  1762.     ConvUsers++;
  1763.   
  1764.     process_commands(cp,m);
  1765.   
  1766.     setflush(m->user,oldflush);
  1767.   
  1768. }
  1769. #endif /* MAILBOX */
  1770.   
  1771. #endif /* CONVERS */
  1772.